package utils

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"math/big"
	"strings"

	"github.com/tjfoc/gmsm/sm2"
	"github.com/tjfoc/gmsm/sm3"
	"github.com/tjfoc/gmsm/sm4"
	"github.com/tjfoc/gmsm/x509"
)

// SM4密钥长度（字节）
const SM4_KEY_LENGTH = 16

// ParsePublicKey 解析公钥PEM格式为SM2公钥对象
func ParsePublicKey(publicKeyPem string) (*sm2.PublicKey, error) {
	// 检查公钥格式
	if len(publicKeyPem) < 10 || publicKeyPem[:10] != "-----BEGIN" {
		return nil, errors.New("公钥不是PEM格式: 必须以-----BEGIN开头")
	}

	// 确保结束标记是完整的
	if !strings.Contains(publicKeyPem, "-----END") {
		return nil, errors.New("公钥PEM格式错误: 缺少-----END标记")
	}

	block, rest := pem.Decode([]byte(publicKeyPem))
	if block == nil {
		// 提供更详细的错误信息
		if len(rest) > 0 {
			return nil, fmt.Errorf("解析公钥PEM格式失败: 剩余%d字节未解析", len(rest))
		}
		return nil, errors.New("解析公钥PEM格式失败: 无法识别的PEM格式")
	}

	// 记录区块类型，帮助调试
	blockType := block.Type

	pubKey, err := x509.ParseSm2PublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("解析SM2公钥失败 (类型: %s): %w", blockType, err)
	}

	return pubKey, nil
}

// ParsePrivateKey 解析私钥PEM格式为SM2私钥对象
func ParsePrivateKey(privateKeyPem string) (*sm2.PrivateKey, error) {
	// 检查私钥格式
	if len(privateKeyPem) < 10 || privateKeyPem[:10] != "-----BEGIN" {
		return nil, errors.New("私钥不是PEM格式: 必须以-----BEGIN开头")
	}

	// 确保结束标记是完整的
	if !strings.Contains(privateKeyPem, "-----END") {
		return nil, errors.New("私钥PEM格式错误: 缺少-----END标记")
	}

	block, rest := pem.Decode([]byte(privateKeyPem))
	if block == nil {
		// 提供更详细的错误信息
		if len(rest) > 0 {
			return nil, fmt.Errorf("解析私钥PEM格式失败: 剩余%d字节未解析", len(rest))
		}
		return nil, errors.New("解析私钥PEM格式失败: 无法识别的PEM格式")
	}

	// 记录区块类型，帮助调试
	blockType := block.Type

	// 尝试直接解析
	priKey, err := x509.ParseSm2PrivateKey(block.Bytes)
	if err == nil {
		return priKey, nil
	}

	// 如果标准解析失败，尝试手动解析EC PRIVATE KEY格式
	// EC PRIVATE KEY的ASN.1结构:
	// ECPrivateKey ::= SEQUENCE {
	//     version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
	//     privateKey     OCTET STRING,
	//     parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
	//     publicKey  [1] BIT STRING OPTIONAL
	// }
	data := block.Bytes
	if len(data) < 40 {
		return nil, fmt.Errorf("无法解析私钥 (类型: %s): 数据太短", blockType)
	}

	// 查找私钥值：寻找0x04后面跟着0x20（32字节长度标识）
	// 这个模式表示一个32字节的OCTET STRING
	for i := 0; i < len(data)-34; i++ {
		if data[i] == 0x04 && data[i+1] == 0x20 {
			// 找到了32字节的OCTET STRING，提取私钥值
			privateKeyBytes := data[i+2 : i+34]

			// 使用现有的HexToPrivateKey函数来避免低级椭圆曲线操作
			privateKeyHex := hex.EncodeToString(privateKeyBytes)
			priv, err := HexToPrivateKey(privateKeyHex)
			if err == nil {
				return priv, nil
			}
		}
	}

	// 如果所有尝试都失败，返回详细错误信息
	return nil, fmt.Errorf("无法解析私钥 (类型: %s): %w", blockType, err)
}

// PublicKeyToHex 将SM2公钥转换为16进制字符串
func PublicKeyToHex(publicKey *sm2.PublicKey) string {
	x := publicKey.X.Bytes()
	y := publicKey.Y.Bytes()

	// 确保x和y是32字节长度
	xPadded := make([]byte, 32)
	yPadded := make([]byte, 32)

	copy(xPadded[32-len(x):], x)
	copy(yPadded[32-len(y):], y)

	return hex.EncodeToString(append(xPadded, yPadded...))
}

// PrivateKeyToHex 将SM2私钥转换为16进制字符串
func PrivateKeyToHex(privateKey *sm2.PrivateKey) string {
	d := privateKey.D.Bytes()

	// 确保d是32字节长度
	dPadded := make([]byte, 32)
	copy(dPadded[32-len(d):], d)

	return hex.EncodeToString(dPadded)
}

// HexToPrivateKey 将16进制字符串转换为SM2私钥
func HexToPrivateKey(hexKey string) (*sm2.PrivateKey, error) {
	d, err := hex.DecodeString(hexKey)
	if err != nil {
		return nil, fmt.Errorf("解码16进制私钥失败: %w", err)
	}

	curve := sm2.P256Sm2()
	priv := new(sm2.PrivateKey)
	priv.Curve = curve
	priv.D = new(big.Int).SetBytes(d)

	// 计算对应的公钥（SM2国密算法需要使用底层椭圆曲线API）
	priv.PublicKey.X, priv.PublicKey.Y = curve.ScalarBaseMult(d) //nolint:staticcheck
	priv.PublicKey.Curve = curve

	return priv, nil
}

// HexToPublicKey 将16进制字符串转换为SM2公钥
func HexToPublicKey(hexKey string) (*sm2.PublicKey, error) {
	if len(hexKey) != 128 {
		return nil, errors.New("无效的公钥16进制字符串长度")
	}

	xHex := hexKey[:64]
	yHex := hexKey[64:]

	x, err := hex.DecodeString(xHex)
	if err != nil {
		return nil, fmt.Errorf("解码公钥X坐标失败: %w", err)
	}

	y, err := hex.DecodeString(yHex)
	if err != nil {
		return nil, fmt.Errorf("解码公钥Y坐标失败: %w", err)
	}

	pub := new(sm2.PublicKey)
	pub.Curve = sm2.P256Sm2()
	pub.X = new(big.Int).SetBytes(x)
	pub.Y = new(big.Int).SetBytes(y)

	return pub, nil
}

// ToBase64String 将字节数组转为Base64字符串
func ToBase64String(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

// FromBase64String 将Base64字符串转为字节数组
func FromBase64String(data string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(data)
}

// ToHexString 将字节数组转为16进制字符串
func ToHexString(data []byte) string {
	return hex.EncodeToString(data)
}

// FromHexString 将16进制字符串转为字节数组
func FromHexString(data string) ([]byte, error) {
	return hex.DecodeString(data)
}

// GenerateSM4Key 生成SM4密钥
func GenerateSM4Key() ([]byte, error) {
	key := make([]byte, SM4_KEY_LENGTH)
	n, err := rand.Read(key)
	if err != nil {
		return nil, fmt.Errorf("生成SM4密钥失败: %w", err)
	}

	if n != SM4_KEY_LENGTH {
		return nil, errors.New("生成的SM4密钥长度不符合要求")
	}

	return key, nil
}

// 检查是否是PEM格式的密钥
func isPEMFormat(key string) bool {
	return len(key) > 10 && key[:10] == "-----BEGIN"
}

// 转换各种格式的私钥为SM2私钥对象
func convertToPrivateKey(privateKey string) (*sm2.PrivateKey, error) {
	if isPEMFormat(privateKey) {
		// 如果是PEM格式，先解析为私钥对象
		return ParsePrivateKey(privateKey)
	} else {
		// 如果是十六进制格式，直接使用原有函数
		return HexToPrivateKey(privateKey)
	}
}

// 转换各种格式的公钥为SM2公钥对象
func convertToPublicKey(publicKey string) (*sm2.PublicKey, error) {
	if isPEMFormat(publicKey) {
		// 如果是PEM格式，先解析为公钥对象
		return ParsePublicKey(publicKey)
	} else {
		// 如果是十六进制格式，直接使用原有函数
		return HexToPublicKey(publicKey)
	}
}

// SM2Sign SM2签名
func SM2Sign(data []byte, privateKey string) ([]byte, error) {
	priKey, err := convertToPrivateKey(privateKey)
	if err != nil {
		return nil, fmt.Errorf("私钥格式转换失败: %w", err)
	}

	// 使用私钥对数据进行签名，生成签名值 - 查看tjfoc/gmsm库的最新API
	r, s, err := sm2.Sm2Sign(priKey, data, []byte(""), rand.Reader)
	if err != nil {
		return nil, fmt.Errorf("SM2签名失败: %w", err)
	}

	// 将签名值转换为DER编码
	signature, err := sm2.SignDigitToSignData(r, s)
	if err != nil {
		return nil, fmt.Errorf("签名结果编码失败: %w", err)
	}

	return signature, nil
}

// SM2Verify SM2验签
func SM2Verify(data, signature []byte, publicKey string) (bool, error) {
	// 尝试解码base64签名
	var signBytes []byte
	var err error

	if len(signature) > 0 && signature[0] != 0x30 { // 不是DER编码开头
		signBytes, err = FromBase64String(string(signature))
		if err != nil {
			signBytes = signature
		}
	} else {
		signBytes = signature
	}

	pubKey, err := convertToPublicKey(publicKey)
	if err != nil {
		return false, fmt.Errorf("公钥格式转换失败: %w", err)
	}

	// 从DER编码的签名中提取r和s
	r, s, err := sm2.SignDataToSignDigit(signBytes)
	if err != nil {
		return false, fmt.Errorf("解析签名失败: %w", err)
	}

	// 验证签名
	return sm2.Sm2Verify(pubKey, data, []byte(""), r, s), nil
}

// SM2Encrypt SM2加密
func SM2Encrypt(plaintext []byte, publicKey string) ([]byte, error) {
	pubKey, err := convertToPublicKey(publicKey)
	if err != nil {
		return nil, fmt.Errorf("公钥格式转换失败: %w", err)
	}

	// 加密数据
	ciphertext, err := sm2.Encrypt(pubKey, plaintext, rand.Reader, sm2.C1C3C2)
	if err != nil {
		return nil, fmt.Errorf("SM2加密失败: %w", err)
	}

	return ciphertext, nil
}

// SM2Decrypt SM2解密
func SM2Decrypt(ciphertext []byte, privateKey string) ([]byte, error) {
	priKey, err := convertToPrivateKey(privateKey)
	if err != nil {
		return nil, fmt.Errorf("私钥格式转换失败: %w", err)
	}

	// 创建原始密文的副本
	originalCiphertext := make([]byte, len(ciphertext))
	copy(originalCiphertext, ciphertext)

	// 尝试多种方式解密
	var plaintext []byte
	var decryptErr error

	// 方法1: 直接解密(C1C3C2模式)
	plaintext, decryptErr = sm2.Decrypt(priKey, ciphertext, sm2.C1C3C2)
	if decryptErr == nil {
		return plaintext, nil
	}
	// 所有尝试都失败，返回最后一个错误
	return nil, fmt.Errorf("SM2解密失败: %w", decryptErr)
}

// SM4ECBEncrypt SM4/ECB/PKCS5Padding加密
func SM4ECBEncrypt(plaintext, key []byte) ([]byte, error) {
	if len(key) != SM4_KEY_LENGTH {
		return nil, fmt.Errorf("SM4密钥长度必须为%d字节", SM4_KEY_LENGTH)
	}

	// 使用ECB模式加密
	ciphertext, err := sm4.Sm4Ecb(key, plaintext, true)
	if err != nil {
		return nil, fmt.Errorf("SM4加密失败: %w", err)
	}

	return ciphertext, nil
}

// SM4ECBDecrypt SM4/ECB/PKCS5Padding解密
func SM4ECBDecrypt(ciphertext, key []byte) ([]byte, error) {
	if len(key) != SM4_KEY_LENGTH {
		return nil, fmt.Errorf("SM4密钥长度必须为%d字节", SM4_KEY_LENGTH)
	}

	// 使用ECB模式解密
	plaintext, err := sm4.Sm4Ecb(key, ciphertext, false)
	if err != nil {
		return nil, fmt.Errorf("SM4解密失败: %w", err)
	}

	return plaintext, nil
}

// ReadRandom 读取随机数
func ReadRandom(b []byte) (int, error) {
	return rand.Read(b)
}

// GetDigestByType 根据摘要算法类型生成摘要
func GetDigestByType(digestType string, data []byte) ([]byte, error) {
	// 根据算法类型计算摘要
	switch digestType {
	case "SM3":
		// 使用SM3算法计算摘要
		hash := sm3.New()
		hash.Write(data)
		return hash.Sum(nil), nil
	case "SHA256":
		// 使用SHA256算法计算摘要
		hash := sha256.New()
		hash.Write(data)
		return hash.Sum(nil), nil
	default:
		return nil, fmt.Errorf("不支持的摘要算法类型: %s", digestType)
	}
}
